package com.pb.infra.oth.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 运算类
 * @author 沈星浩
 * @date 2022/8/18
 */
public class BatchUtils {
    /**
     * 求两个数之间的和，返回字符串形式的值；注意：如果其中任何一个参数为空或者为空字符串，都返回空值
     *
     * @param addend1
     *            加数
     * @param addend2
     *            加数
     * @return
     */
    public static String getSumOfDecimals(String addend1, String addend2) {
        if (addend1 == null || addend1.trim().length() <= 0 || addend2 == null || addend2.trim().length() <= 0) {
            return "";
        }
        BigDecimal addend1Value = new BigDecimal(addend1);
        BigDecimal addend2Value = new BigDecimal(addend2);
        BigDecimal result = addend1Value.add(addend2Value);
        return result.toString();
    }
    /**
     * 求两个数之间的差，返回字符串形式的值；注意：如果其中任何一个参数为空或者为空字符串，都返回空值
     *
     * @param minuendStr
     *            被减数
     * @param subtrahendStr
     *            减数
     * @return
     */
    public static String getMinusOfDecimals(String minuendStr, String subtrahendStr) {
        if (minuendStr == null || minuendStr.trim().length() <= 0 || subtrahendStr == null || subtrahendStr.trim().length() <= 0) {
            return "";
        }
        BigDecimal subtrahend = new BigDecimal(subtrahendStr);
        BigDecimal minuend = new BigDecimal(minuendStr);
        BigDecimal result = minuend.subtract(subtrahend);
        return result.toString();
    }
    /**
     * 求两个数之间的乘积，返回字符串形式的值；注意：如果其中任何一个参数为空或者为空字符串，都返回空值
     *
     * @param mult1Str
     *            乘数1
     * @param mult2Str
     *            乘数2
     * @return
     */
    public static String getMultiplyOfDecimals(String mult1Str, String mult2Str) {
        if (mult1Str == null || mult1Str.trim().length() <= 0 || mult2Str == null || mult2Str.trim().length() <= 0) {
            return "";
        }
        BigDecimal mult1 = new BigDecimal(mult1Str);
        BigDecimal mult2 = new BigDecimal(mult2Str);
        BigDecimal result = mult1.multiply(mult2);
        return result.toString();
    }

    /** 用日利率根据金额、利率、开始日期、结束日期、利率计算方式计算利息
     *
     * @author 沈星浩
     * @date 2020年5月21日
     * @param amtStr  金额
     * @param rateStr 利率
     * @param startDate  开始日期
     * @param endDate 结束日期
     * @param interCalcType 利率计算方式
     * @param addDays 需要增加或减少(addDays为负数)的天数
     * @return
     */
    public static Double computeInterestAmt(String amtStr, String rateStr, Date startDate, Date endDate, String interCalcType, int addDays) {
        if (amtStr == null || amtStr.trim().length() <= 0 ||
                rateStr == null || rateStr.trim().length() <= 0 ||
                startDate == null || endDate == null || interCalcType == null) {
            throw new RuntimeException("利息计算：信息不能为空！");
        }

        BigDecimal amt = new BigDecimal(amtStr); // 金额
        BigDecimal rate = new BigDecimal(rateStr); // 利率
        BigDecimal daysOfYear = new BigDecimal(getInterDaysOfYear(interCalcType, startDate,endDate)); // 年利率天数
        // 实际/360、实际/365、实际/实际
        if (Constant.INTER_CALC_TYPE_DIV360.equals(interCalcType.trim())
                || Constant.INTER_CALC_TYPE_DIV365.equals(interCalcType.trim())
                || Constant.INTER_CALC_TYPE_DIVACT.equals(interCalcType.trim())) {

            BigDecimal daysOfComputeRate = new BigDecimal(getDaysOfComputeRate(startDate, endDate)).add(new BigDecimal(addDays + "")); // 计息天数

            // 乘除计算的顺序对结果是否有影响？
            BigDecimal resultDecimal = ((amt.multiply(rate).multiply(daysOfComputeRate)).divide(new BigDecimal("100"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP).divide(daysOfYear, Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP));
            Double result = resultDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
            return result;
        }
        // 30/360
        else if (Constant.INTER_CALC_TYPE_30DIV360.equals(interCalcType.trim())) {
            int calcDays = 0;
            Double result = 0D;
            Long startDateMonth = getMonthOfDate(startDate);
            Long startDateDay = getDayOfDate(startDate);
            Long endDateMonth = getMonthOfDate(endDate);
            Long endDateDay = getDayOfDate(endDate);
            Long strarDateYear = getYearOfDate(startDate);
            Long endDateYear = getYearOfDate(endDate);
            if (startDateMonth.compareTo(endDateMonth) == 0 && startDateDay.compareTo(endDateDay) == 0) {
                Long days = (endDateYear - strarDateYear) * 360;
                if (startDateMonth == 2 && startDateDay == 28 && endDateDay == 28 && endDateMonth == 2) {
                    // 开始年以非闰年开始
                    if (!ChineseCalendarGB.isGregorianLeapYear(strarDateYear.intValue())) {
                        days = days - 2;
                    }
                }
                // 开始年和结束年都是闰年，且2者都是29号
                if (startDateMonth == 2 && startDateDay == 29 && endDateDay == 29 && endDateMonth == 2) {
                    days = days - 1;
                }
                calcDays = days.intValue();
                BigDecimal results = (amt.multiply(rate).multiply(new BigDecimal(calcDays + "")))
                        .divide(new BigDecimal("100"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP)
                        .divide(new BigDecimal("360"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP);
                if (results != null) {
                    result = results.doubleValue();
                }
            } else {
                // 获取开始日的所在月最后一天
                // startDate, endDate
                Date startDateMonthLastDay = getLastDayOfMonthByDate(startDate);
                Long startDateMonthLastDayDay = getDayOfDate(startDateMonthLastDay);
                int startDays;
                if (startDateMonthLastDayDay == 28) {
                    if (startDateDay < 28) {
                        startDays = getDaysBetweenDates(startDate, startDateMonthLastDay) + 3;
                    } else {
                        startDays = getDaysBetweenDates(startDate, startDateMonthLastDay) + 1;
                    }
                } else if (startDateMonthLastDayDay == 29) {
                    if (startDateDay < 29) {
                        startDays = getDaysBetweenDates(startDate, startDateMonthLastDay) + 2;
                    } else {
                        startDays = getDaysBetweenDates(startDate, startDateMonthLastDay) + 1;
                    }
                } else if (startDateMonthLastDayDay == 30) {
                    startDays = getDaysBetweenDates(startDate, startDateMonthLastDay) + 1;
                } else if (startDateMonthLastDayDay == 31) {
                    if (startDateDay < 31) {
                        startDays = getDaysBetweenDates(startDate, startDateMonthLastDay);
                    } else {
                        startDays = getDaysBetweenDates(startDate, startDateMonthLastDay) + 1;
                    }
                } else {
                    startDays = getDaysBetweenDates(startDate, startDateMonthLastDay);
                }

                // 整月开始日
                Date monthCalcFirstDay = getDateAfterDays(startDateMonthLastDay, 1);
                // 获取结束日所在月份的第一天
                Date endDateMonthFirstDay = getFirstDayOfMonthDate(endDate);
                int endDays = getDaysBetweenDates(endDateMonthFirstDay, endDate);
                // 整月结束日
                Date monthCalcLastDay = endDateMonthFirstDay;
                int monthNum = getMonthsBetWeenDays(monthCalcFirstDay, monthCalcLastDay);
                // 总天数=开头天数+月数*30+结束天数
                calcDays = startDays + monthNum * 30 + endDays;

                // 1.如果最后一天是31
                if (endDateDay == 31) {
                    if (startDateDay == startDateMonthLastDayDay.intValue() || (startDateMonthLastDayDay == 31 && startDateDay >= 30)) {
                        calcDays = calcDays - 1;
                    }
                }

                BigDecimal results = (amt.multiply(rate).multiply(new BigDecimal(calcDays + ""))).divide(new BigDecimal("100"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP).divide(new BigDecimal("360"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP);
                if (results != null) {
                    result = results.setScale(2, RoundingMode.HALF_UP).doubleValue();
                }
            }
            return result;

        } else if (Constant.INTER_CALC_TYPE_30DIV365.equals(interCalcType.trim())) {
            double monthNum = 0.0;

            int days = BatchUtils.getDaysBetweenDates(startDate, endDate);
            int completeMonthNum = days / 30;
            int leftDays = days % 30;
            if (leftDays >= 28) {
                completeMonthNum++;
                monthNum = completeMonthNum;
            } else if (leftDays < 6) {
                monthNum = completeMonthNum;
            } else {
                monthNum = completeMonthNum + (new BigDecimal(leftDays).divide(new BigDecimal("30"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP)).doubleValue();
            }

            // 整月利息
            BigDecimal monthInterAmt = ((amt.multiply(rate).multiply(new BigDecimal(monthNum + ""))).divide(new BigDecimal("100"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP).divide(new BigDecimal("365").divide(new BigDecimal("30"), RoundingMode.HALF_UP),
                    Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP));
            Double result = monthInterAmt.setScale(2, RoundingMode.HALF_UP).doubleValue();
            return result;
        } else {
            throw new RuntimeException("未知的利息计算方式！");
        }
    }

    /**
     * 根据利息计算方式返回年利率天数
     * @author 沈星浩
     * @date 2020年5月21日
     * @param interCalcType
     * @param yearDate
     * @param calcEndDate
     * @return
     */
    public static int getInterDaysOfYear(String interCalcType, Date yearDate,Date calcEndDate) {
        if (interCalcType == null || interCalcType.trim().length() <= 0) {
            throw new RuntimeException("利息计算方式不能为空！");
        }
        if (Constant.INTER_CALC_TYPE_DIV360.equals(interCalcType.trim())) {
            return 360;
        } else if (Constant.INTER_CALC_TYPE_DIV365.equals(interCalcType.trim())) {
            return 365;
        } else if (Constant.INTER_CALC_TYPE_30DIV360.equals(interCalcType.trim())) {
            return 360;
        } else if (Constant.INTER_CALC_TYPE_30DIV365.equals(interCalcType.trim())) {
            return 365;
        }
        //实际/实际的逻辑进行了调整，如果计息区间内，含有2月29号，则这个计息区间的年利率天数算366天
        else if (Constant.INTER_CALC_TYPE_DIVACT.equals(interCalcType.trim())) {
            if (yearDate == null) {
                return 365;
            } else {
//				return BatchUtils.getActDaysOfYear(yearDate);
                if(getIsExistLeapDay(yearDate,calcEndDate)){
                    return 366;
                }else{
                    return 365;
                }
            }
        } else {
            throw new RuntimeException("未知的利息计算方式：" + interCalcType);
        }
    }

    /**
     * 根据开始日期和结束日期返回计息天数,不考虑小时、分、秒 结束日期不能小于开始日期，否则抛出运行时异常
     * @author 沈星浩
     * @date 2020年5月21日
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getDaysOfComputeRate(Date startDate, Date endDate) {
        if(startDate == null || endDate == null){
            return 0;
        }

        if(endDate.compareTo(startDate)<0){


            throw new RuntimeException("结束日期不能小于开始日期！");
        }
        // return getDaysBetweenDates(startDate,endDate) + 1;
        return getDaysBetweenDates(startDate, endDate);
    }

    /**
     * 获得给定日期的月份<br>
     * 如果参数为空则抛出运行时异常
     *
     * @param date
     * @return
     */
    public static Long getMonthOfDate(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空！");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        return (long) (cal.get(Calendar.MONTH) + 1);
    }


    /**
     * 获得给定日期的日子 例如：2012-12-20 将返回20<br>
     * 如果参数为空则抛出运行时异常
     * @author 沈星浩
     * @date 2020年5月21日
     * @param date
     * @return
     */
    public static Long getDayOfDate(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空！");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        return (long) (cal.get(Calendar.DATE));
    }

    /**
     * 获得给定日期的年份<br>
     * 如果参数为空则抛出运行时异常
     *
     * @param date
     * @return
     */
    public static Long getYearOfDate(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空！");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        return (long) (cal.get(Calendar.YEAR));
    }

    /**
     * 获得给定日期当月的最后一天 如果参数为null，则抛出NullPointerException
     * @author 沈星浩
     * @date 2020年5月20日
     * @param date
     * @return
     */
    public static Date getLastDayOfMonthByDate(Date date) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1);
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    /**
     * 返回两个日期之间的天数,不考虑小时、分、秒 结束日期小于开始日期则返回负数
     * @author 沈星浩
     * @date 2020年5月20日
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getDaysBetweenDates(Date startDate, Date endDate) {
        try {
            if (startDate == null || endDate == null) {
                throw new RuntimeException("日期不能为空！");
            }
            Date start = Constant.getDATE_FORMAT_YYYYMMDD().parse(Constant.getDATE_FORMAT_YYYYMMDD().format(startDate));
            Date end = Constant.getDATE_FORMAT_YYYYMMDD().parse(Constant.getDATE_FORMAT_YYYYMMDD().format(endDate));

            long result = (end.getTime() - start.getTime()) / (1000L * 60 * 60 * 24);

            return (int) result;
        } catch (Exception e) {
            throw new RuntimeException("计算两个日期之间天数错误！", e);
        }
    }

    /**
     * 获得给定日期之后一定天数的日期 如果给定的日期为空则抛出运行时异常
     * @author 沈星浩
     * @date 2020年5月20日
     * @param date
     * @param days
     * @return
     */
    public static Date getDateAfterDays(Date date, int days) {
        if (date == null) {
            throw new RuntimeException("日期不能为空!");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(Calendar.DATE, days);
        return cal.getTime();
    }

    /**
     * 获得给定日期当月的第一天 如果参数为null，则抛出NullPointerException
     * @author 沈星浩
     * @date 2020年5月21日
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonthDate(Date date) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        return cal.getTime();
    }
    /**
     * 获得给定日期之后一定月数的日期 如果给定的日期为空则抛出运行时异常
     * @author 沈星浩
     * @date 2020年5月20日
     * @param date
     * @param months
     * @return
     */
    public static Date getDateAfterMonths(Date date, int months) {
        if (date == null) {
            throw new RuntimeException("日期不能为空!");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(Calendar.MONTH, months);
        return cal.getTime();
    }
    public static void main(String [] args){
        String dateStr ="20220525";
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
        Date date = DateTimeUtil.getStringToDate(dateStr,sf);

        Date newDate = getDateAfterQuarter(date,1);

    }
    /**
     * 获取指定日期后指定季度的日期，如果给定的日期为空则抛出运行时异常
     * 中广核用，指定季度3,6,9,12，例如当前日期2022/8/23，后续就是2022/9/23、2022/12/23、2023/3/23
     * @author 沈星浩
     * @date 2022/8/23
     */
    public static Date getDateAfterQuarter(Date date,int quarter){
        if (date == null) {
            throw new RuntimeException("日期不能为空!");
        }
        int months = quarter*3;
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.MONTH, (((int) cal.get(Calendar.MONTH)) / 3) * 3-1);//这里是本季度初的日期
        cal.add(Calendar.MONTH,3);//这是本季度末的日期
        cal.add(Calendar.MONTH,months);//这是季度后的日期
        return cal.getTime();
    }
    /**
     * 获得给定日期之间的月数
     * @author 沈星浩
     * @date 2020年5月21日
     * @param monthCalcFirstDay
     * @param monthCalcLastDay
     * @return
     */
    private static int getMonthsBetWeenDays(Date monthCalcFirstDay, Date monthCalcLastDay) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(monthCalcFirstDay);
        c2.setTime(monthCalcLastDay);
        int year = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
        return year * 12 + c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH);
    }

    /**
     *  计算两个日期之间，是否存在闰年闰月闰日：xxxx年2月29号
     * @author 沈星浩
     * @date 2020年5月21日
     * @param startDate
     * @param endDate
     * @return
     */
    public static boolean getIsExistLeapDay(Date startDate, Date endDate) {
        boolean flag = false;
        int stYear = getYearOfDate(startDate).intValue();
        int stMonth= getMonthOfDate(startDate).intValue();
        int stDay = getDayOfDate(startDate).intValue();

        int endYear = getYearOfDate(endDate).intValue();
        int endMonth= getMonthOfDate(endDate).intValue();
        int endDay = getDayOfDate(endDate).intValue();
        int days = 0;

        while(stYear <= endYear){
            //当循环至结束年、结束月的时候，1.判断下开始日期是否大于结束日 2.结束日是否小于29号，任一添加满足了，均不需要再继续循环下去了，程序结束，返回flag
            if(stYear == endYear && stMonth == endMonth && (stDay >= endDay || endDay < 29)){
                break;
            }
            if(stMonth == 2){//从开始年月循环，如果循环至2月份，需判断2月总实际总天数是否为29，非2月无需判断
                Calendar calendar = Calendar.getInstance();
                calendar.set(Calendar.DATE, 1);
                calendar.set(Calendar.MONTH, stMonth - 1);
                calendar.set(Calendar.YEAR, stYear);
                days = calendar.getActualMaximum(Calendar.DATE);//获取xxxx年2月最大实际天数
                if(days == 29){//只判断2月是否有29号，其他月份必定有29号。如果获取xxxx年2月有29天，退出循环并终止程序。
                    flag = true;
                    break;
                }else{
                    stMonth ++;
                }
            }else{//其他月份，逐一递增月份
                stMonth ++;
            }
            if(stMonth > 12){//当前循环月份为12时，年份+1，月份设置为第1个月，进入下一年1月的循环
                stMonth = 1;
                stYear ++;
            }
        }
        return flag;
    }
    /**
     * 获取计息截止日
     * @author 沈星浩
     * @date 2020年5月21日
     * @param planRepayDte
     * @param actRepayDte
     * @param holidayCalcType
     * @return
     */
    public static Date getCalcEndDate(Date planRepayDte, Date actRepayDte, String holidayCalcType) {
        if (holidayCalcType == null || holidayCalcType.trim().length() <= 0) {
            return planRepayDte;
        }
        if (Constant.HOLIDAY_CALC_TYPE_PLAN.equals(holidayCalcType.trim())) {
            return planRepayDte;
        } else if (Constant.HOLIDAY_CALC_TYPE_PAY.equals(holidayCalcType.trim())) {
            return actRepayDte;
        } else {
            throw new RuntimeException("未知的节假日算息方式！");
        }
    }
    /**判断两个字符串是否相同，如果都为空返回true
     *
     * @author 沈星浩
     * @date 2020年5月21日
     * @param str1
     * @param str2
     * @return
     */
    public static boolean isEqualString(String str1, String str2) {
        if (str1 == null && str2 == null) {
            return true;
        }
        if (str1 == null) {
            return false;
        }
        if (str2 == null) {
            return false;
        }
        return str1.trim().equals(str2.trim());
    }
    /**
     * 将destination的月对应的日设为source的月对应的日 例：source = 20110130 ,destination =
     * 20110320 ,则返回20110330；source = 20110130 ,destination = 20110220
     * ,则返回20110228 参数为空则抛出异常
     * @author 沈星浩
     * @date 2020年5月20日
     * @param source
     * @param destination
     * @return
     */
    public static Date setSameDayOfMonth(Date source, Date destination) {
        if (source == null || destination == null) {
            throw new RuntimeException("日期不能为空！");
        }
        GregorianCalendar sourceCal = new GregorianCalendar();
        sourceCal.setTime(source);
        GregorianCalendar destinationCal = new GregorianCalendar();
        destinationCal.setTime(destination);
        int monthBefore = destinationCal.get(Calendar.MONTH);
        destinationCal.set(Calendar.DATE, sourceCal.get(Calendar.DATE));
        int monthAfter = destinationCal.get(Calendar.MONTH);
        if (monthBefore != monthAfter) {
            destinationCal.add(Calendar.MONTH, -1);
            destinationCal.setTime(BatchUtils.getLastDayOfMonthByDate(destinationCal.getTime()));
        }
        return destinationCal.getTime();
    }
    /**
     * 判断给定日期是否当月的最后一天 参数为空则抛出运行时异常
     * @author 沈星浩
     * @date 2020年5月20日
     * @param date
     * @return
     */
    public static boolean isLastDayOfMonth(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空！");
        }
        if (date.compareTo(BatchUtils.getLastDayOfMonthByDate(date)) == 0) {
            return true;
        }
        return false;
    }
    /**
     * 根据上次付款日及相关属性取下次付款日
     * @author 沈星浩
     * @date 2020年5月20日
     * @param paymentFreq //付费频率
     * @param paymentFreqMult //付费频率单位
     * @param lastPaymentDate //上次付款日
     * @param maturityDte //结束日
     * @param firstPaymentDate //首次付款日
     * @return
     */
    public static Date getNextPayDateNew(int paymentFreq,
                                         String paymentFreqMult,
                                         Date lastPaymentDate,
                                         Date maturityDte,
                                         Date firstPaymentDate) {
        if (StringUtil.isEmpty(paymentFreq) || paymentFreqMult == null
                || paymentFreqMult.trim().length() <= 0
                || lastPaymentDate == null || maturityDte == null
                || firstPaymentDate == null) {
            throw new RuntimeException("获取下次付款日错误！信息不能为空!");
        }
        if (lastPaymentDate.compareTo(maturityDte) > 0) {
            throw new RuntimeException("上次付款日不能大于到期日！");
        }
        Date result;
        if (Constant.PAYMENT_FREQ_MULT_DAY.equals(paymentFreqMult)) {
            result = getDateAfterDays(lastPaymentDate, paymentFreq);
            return result;
        } else if (Constant.PAYMENT_FREQ_MULT_MONTH.equals(paymentFreqMult)) {
            result = getDateAfterMonths(lastPaymentDate,paymentFreq);
        } else if (Constant.PAYMENT_FREQ_MULT_SEASON.equals(paymentFreqMult)) {
            //result = getDateAfterQuarter(lastPaymentDate, paymentFreq);
            result = getDateAfterMonths(lastPaymentDate, paymentFreq * 3);
        } else if (Constant.PAYMENT_FREQ_MULT_YEAR.equals(paymentFreqMult)) {
            result = getDateAfterMonths(lastPaymentDate,  paymentFreq* 12);
        } else {
            throw new RuntimeException("未知的付款频率单位！");
        }
        result = setSameDayOfMonth(firstPaymentDate, result);
        if (BatchUtils.isLastDayOfMonth(firstPaymentDate)) {
            result = BatchUtils.getLastDayOfMonthByDate(result);
        }
        if (result.compareTo(maturityDte) > 0) {
            result = maturityDte;
        }

        return result;
    }
    /**
     * 根据本期付息日获得本期计息终止日
     * intCalculateCde 可传一个默认值Constant.INTEREST_CALCULATE_CODE_NEXT_DAY_COUNT
     * @author 沈星浩
     * @date 2022/8/23
     */
    public static Date getEndCountInterDate(Date endDate,Date preDate,String intCalculateCde) {
        if (preDate.compareTo(endDate) == 0) {
            return endDate;
        }
        if (Constant.INTEREST_CALCULATE_CODE_FIRST_DAY_COUNT.equals(intCalculateCde)) {
            return DateTimeUtil.getNextDatesByDate(preDate, 1);
        } else if (Constant.INTEREST_CALCULATE_CODE_NEXT_DAY_COUNT.equals(intCalculateCde)) {
            return preDate;
        }
        return null;
    }
    /**
     *  用日利率根据积数、利率、利率计算方式计算利息，积数计算时间按照一天算
     * @author 沈星浩
     * @date 2020年5月21日
     * @param amtStr 金额
     * @param rateStr 利率
     * @param interCalcType  利率计算方式
     * @return
     */
    public static Double computePdtInterestAmt(String amtStr, String rateStr, String interCalcType) {
        if (amtStr == null || amtStr.trim().length() <= 0 || rateStr == null || rateStr.trim().length() <= 0 || interCalcType == null) {
            throw new RuntimeException("利息计算：信息不能为空！");
        }
        BigDecimal amt = new BigDecimal(amtStr); // 金额
        BigDecimal rate = new BigDecimal(rateStr); // 利率
        BigDecimal daysOfYear = new BigDecimal(getInterDaysOfYear(interCalcType, null,null)); // 年利率天数
        BigDecimal daysOfComputeRate = new BigDecimal("1"); // 计息天数

        // 乘除计算的顺序对结果是否有影响？
        BigDecimal resultDecimal = ((amt.multiply(rate).multiply(daysOfComputeRate)).divide(new BigDecimal("100"), Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP).divide(daysOfYear, Constant.DIVIDE_ROUND_LENGTH, RoundingMode.HALF_UP));
        Double result = resultDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
        return result;
    }
    /**
     * 根据上期付息日获得本期计息开始日
     * @param acctDate
     * @param actDate
     * @param intCalculateCde
     * @return
     * @author 曹振锋
     * @date 2020年6月10日
     */
    public static Date getCountInterDate(Date acctDate, Date actDate, String intCalculateCde) {
        if (actDate.compareTo(acctDate) == 0) {
            return acctDate;
        }
        if (Constant.INTEREST_CALCULATE_CODE_FIRST_DAY_COUNT.equals(intCalculateCde)) {
            return DateTimeUtil.getNextDatesByDate(actDate, 1);
        } else if (Constant.INTEREST_CALCULATE_CODE_NEXT_DAY_COUNT.equals(intCalculateCde)) {
            return actDate;
        }
        return null;
    }

    /**
    * @Description: 福费廷计算利息 todo
    * @Author: 贾真行
    * @Date: 2023/1/12
    * @Time: 17:20
    * @Param:
    * @Return:
    */
    public static Date forfaiting(){
        return null;
    }


    /**
    * @Description: 高精度的加法运算
    * @Author: 贾真行
    * @Date: 2023/2/21
    * @Time: 10:23
    * @Param:
    * @Return:
    */
    public static double bigDecimalAdd(double addOne ,double addTwo){
        //创建BigDecimal对象
        BigDecimal b1=new BigDecimal(addOne);
        BigDecimal b2=new BigDecimal(addTwo);
        return b1.add(b2).doubleValue();
    }

    /**
    * @Description: 高精度运算减法
    * @Author: 贾真行
    * @Date: 2023/2/21
    * @Time: 10:24
    * @Param:
    * @Return:
    */
    public static double bigDecimalSub(double subOne,double subTwo){
        BigDecimal b1=new BigDecimal(subOne);
        BigDecimal b2=new BigDecimal(subTwo);
        return b1.subtract(b2).doubleValue();
    }

    /**
    * @Description: 高精度的乘法
    * @Author: 贾真行
    * @Date: 2023/2/21
    * @Time: 10:24
    * @Param:
    * @Return:
    */
    public static double bigDecimalMul(double mulOne,double mulTwo){
        BigDecimal b1=new BigDecimal(mulOne);
        BigDecimal b2=new BigDecimal(mulTwo);
        return b1.multiply(b2).doubleValue();
    }

    /**
    * @Description: 高精度除法
    * @Author: 贾真行
    * @Date: 2023/2/21
    * @Time: 10:24
    * @Param:
    * @Return:
    */
    public static double bigDecimalDiv(double divOne,double divTwo){
        BigDecimal b1=new BigDecimal(divOne);
        BigDecimal b2=new BigDecimal(divTwo);
        return b1.divide(b2).doubleValue();//这里可以设置保留精度，保留位数下面我们在细细介绍。
    }



    /**
     * @param roundDate
     * @param length 保留小数后的位数
     * @Author: 贾真行
     * @return 返回四舍五入后的参数
     */
    public static double bigDecimalRound(double roundDate,int length){
        BigDecimal b1=new BigDecimal(roundDate);
        BigDecimal b2=new BigDecimal(1);
        //第三个参数是表示四舍五入操作，这里传入的参数需要时字符串，不然可能不对下面我在介绍。
        return b1.divide(b2, length, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * @param roundDate
     * @param length
     * @return 返回四舍五入后的参数
     */
    public static double bigDecimalStringRound(String roundDate,int length){
        BigDecimal b1=new BigDecimal(roundDate);
        BigDecimal b2=new BigDecimal(1);
        return b1.divide(b2, length, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

}
